package com.wk.code.wkserver.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wk.code.wkserver.constant.Constant;
import com.wk.code.wkserver.constant.EmailConstant;
import com.wk.code.wkserver.constant.NumberConstant;
import com.wk.code.wkserver.constant.enums.*;
import com.wk.code.wkserver.entity.*;
import com.wk.code.wkserver.exception.BizException;
import com.wk.code.wkserver.manager.AsyncTaskManager;
import com.wk.code.wkserver.mapper.UserWithdrawMapper;
import com.wk.code.wkserver.request.admin.AdminUserWithdrawRequest;
import com.wk.code.wkserver.request.admin.WithdrawVerifyRequest;
import com.wk.code.wkserver.request.app.UserWithdrawRequest;
import com.wk.code.wkserver.request.base.BasePageRequest;
import com.wk.code.wkserver.response.admin.AdminVerifyRecordResponse;
import com.wk.code.wkserver.response.admin.UserWithdrawResponse;
import com.wk.code.wkserver.response.app.BalanceDetailInResponse;
import com.wk.code.wkserver.response.app.BalanceDetailResponse;
import com.wk.code.wkserver.response.app.EstimateDetailInResponse;
import com.wk.code.wkserver.response.app.EstimateDetailResponse;
import com.wk.code.wkserver.response.base.PageInfo;
import com.wk.code.wkserver.service.*;
import com.wk.code.wkserver.utils.DataUtils;
import com.wk.code.wkserver.utils.DateUtils;
import com.wk.code.wkserver.utils.IdWorkUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author wq
 * @since 2021-08-15
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class UserWithdrawServiceImpl extends ServiceImpl<UserWithdrawMapper, UserWithdraw> implements IUserWithdrawService {

    @Resource
    private IUserAccountService userAccountService;

    @Resource
    private IUserAccountRecordService userAccountRecordService;

    @Resource
    private IAdminVerifyRecordService adminVerifyRecordService;

    @Resource
    private IDemandService demandService;

    @Resource
    private IDemandOrderService demandOrderService;

    @Resource
    private IMailService mailService;

    @Resource
    private AsyncTaskManager asyncTaskManager;

    @Resource
    private IUserService userService;

    @Resource
    private IUserInfoService userInfoService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdraw(Integer userId, UserWithdrawRequest request) {
        UserAccount userAccount = userAccountService.selectUserAccount(userId);
        User user = userService.selectById(userId);
        checkParams(request, userAccount, user);
        UserWithdraw userWithdraw = new UserWithdraw();
        userWithdraw.setMobile(user.getMobile());
        userWithdraw.setUserId(userId);
        userWithdraw.setWithdrawAmount(new BigDecimal(request.getWithdrawAmount()));
        userWithdraw.setAlipayAccount(request.getAlipayAccount());
        userWithdraw.setRealName(request.getRealName());
        userWithdraw.setNickname(user.getNickname());
        userWithdraw.setStatus(WithdrawStatusEnum.TO_VERIFY.getCode());
        //生成体现记录
        save(userWithdraw);
        //扣减余额
        userAccountService.decreaseBalance(userId, new BigDecimal(request.getWithdrawAmount()));
        UserAccount userAccountAfter = userAccountService.selectUserAccount(userId);
        //增加技术账户记录
        userAccountRecordService.saveRecord(userId, new BigDecimal(request.getWithdrawAmount()),
                IncomeTypeEnum.OUT.getCode(), AccountTypeEnum.WITHDRAW.getCode(), userAccountAfter.getBalance(), userWithdraw.getId());

    }

    @Override
    public BalanceDetailResponse balanceDetail(Integer userId, BasePageRequest request) {
        UserAccount userAccount = userAccountService.selectUserAccount(userId);
        if (Objects.isNull(userAccount)) {
            throw new BizException("账户不存在哦");
        }
        BalanceDetailResponse response = new BalanceDetailResponse();
        UserInfo userInfo = userInfoService.getOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getUserId, userId));
        if (Objects.nonNull(userInfo)) {
            response.setAlipayAccount(userInfo.getAlipayAccount());
            response.setRealName(userInfo.getRealName());
        }
        response.setTotalIncome(userAccount.getBalance());
        //查询我的余额明细
        IPage<UserAccountRecord> page = new Page<>(request.getPageNumber(), request.getPageSize());
        LambdaQueryWrapper<UserAccountRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserAccountRecord::getUserId, userId);
        wrapper.orderByDesc(UserAccountRecord::getCreateTime);
        List<UserAccountRecord> records = userAccountRecordService.page(page, wrapper).getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            List<BalanceDetailInResponse> list = records.stream().map(x -> {
                BalanceDetailInResponse detail = new BalanceDetailInResponse();
                detail.setBalance(x.getBalance());
                detail.setCreateTime(DateUtils.localDateTime2DateStr(DateUtils.YYYY_MM_DD_HH_MM_SS, x.getCreateTime()));
                //接单收益
                detail.setAccountTypeName(AccountTypeEnum.getValue(x.getAccountType()));
                if (x.getType().equals(IncomeTypeEnum.OUT.getCode())) {
                    detail.setAmount(Constant.OUT + x.getAmount().toString());
                } else {
                    detail.setAmount(Constant.IN + x.getAmount().toString());
                }
                return detail;
            }).collect(Collectors.toList());
            response.setDetailList(list);
        }
        return response;
    }

    @Override
    public EstimateDetailResponse estimateDetail(Integer userId, BasePageRequest request) {
        EstimateDetailResponse response = new EstimateDetailResponse();
        IPage<DemandOrder> page = new Page<>(request.getPageNumber(), request.getPageSize());
        LambdaQueryWrapper<DemandOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DemandOrder::getTechUserId, userId);
        //订单在进行中的就是预计收入列表
        wrapper.eq(DemandOrder::getTechOrderStatus, TechOrderStatusEnum.PROCESSING.getCode());
        wrapper.orderByDesc(DemandOrder::getCreateTime);
        List<DemandOrder> records = demandOrderService.page(page, wrapper).getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            List<EstimateDetailInResponse> list = records.stream().map(x -> {
                EstimateDetailInResponse detail = new EstimateDetailInResponse();
                detail.setDemandId(x.getDemandId());
                detail.setTechAmount(Constant.IN + x.getTechAmount().toString());
                detail.setDemandNo(Constant.DEMAND_PREFIX + IdWorkUtils.getDemandNo(String.valueOf(x.getId())));
                Demand demand = demandService.selectOrderDemand(x.getDemandId());
                if (Objects.nonNull(demand)) {
                    detail.setTitle(demand.getTitle());
                }
                detail.setCreateTime(DateUtils.localDateTime2DateStr(DateUtils.YYYY_MM_DD_HH_MM_SS, x.getCreateTime()));
                return detail;
            }).collect(Collectors.toList());
            BigDecimal decimal = records.stream().map(DemandOrder::getTechAmount).reduce(new BigDecimal("0.00"), BigDecimal::add);
            if (Objects.nonNull(decimal)) {
                response.setEstimateTotalIncome(decimal);
            } else {
                response.setEstimateTotalIncome(new BigDecimal("0.00"));
            }
            response.setDetailList(list);
        }
        return response;
    }

    @Override
    public PageInfo<UserWithdrawResponse> pageList(AdminUserWithdrawRequest request) {
        LambdaQueryWrapper<UserWithdraw> wrapper = buildWrapper(request);
        IPage<UserWithdraw> page = new Page<>(request.getPageNumber(), request.getPageSize());
        wrapper.orderByDesc(UserWithdraw::getCreateTime);
        List<UserWithdraw> records = baseMapper.selectPage(page, wrapper).getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            List<UserWithdrawResponse> list = records.stream().map(x -> {
                UserWithdrawResponse response = new UserWithdrawResponse();
                BeanUtils.copyProperties(x, response);
                response.setCreateTime(DateUtils.localDateTime2Date(x.getCreateTime()));
                response.setUpdateTime(DateUtils.localDateTime2Date(x.getUpdateTime()));
                return response;
            }).collect(Collectors.toList());
            return new PageInfo<>(page.getTotal(), list);
        }
        return null;
    }

    @Override
    public void verify(Integer sysUserId, WithdrawVerifyRequest request) {
        UserWithdraw userWithdraw = baseMapper.selectById(request.getId());
        if (Objects.isNull(userWithdraw)) {
            throw new BizException("提现数据有误");
        }
        //审核通过
        if (request.getVerifyStatus().equals(AdminVerifyStatusEnum.VERIFY_PASS.getCode())) {
            //修改提现状态
            userWithdraw.setStatus(WithdrawStatusEnum.VERIFY_PASS.getCode());
            updateById(userWithdraw);
            //修改用户的提现ID为提现中为提现完成
            UserAccountRecord userAccountRecord = userAccountRecordService.selectRecordByWithdrawId(userWithdraw.getId());
            if (Objects.nonNull(userAccountRecord)) {
                userAccountRecord.setAccountType(AccountTypeEnum.WITHDRAW_SUCCESS.getCode());
                userAccountRecordService.updateById(userAccountRecord);
            }
            //发送转账成功通知邮件
            asyncTaskManager.execute(() -> sendTransMoneyMail(WithdrawStatusEnum.VERIFY_PASS.getCode(),
                    userWithdraw.getUserId(), null, userWithdraw.getWithdrawAmount()));

        } else {
            //不通过
            userWithdraw.setStatus(WithdrawStatusEnum.VERIFY_REJECT.getCode());
            updateById(userWithdraw);

            //修改用户的提现ID为提现中为提现完成
            UserAccountRecord userAccountRecord = userAccountRecordService.selectRecordByWithdrawId(userWithdraw.getId());
            if (Objects.nonNull(userAccountRecord)) {
                userAccountRecord.setAccountType(AccountTypeEnum.WITHDRAW_FAIL.getCode());
                userAccountRecordService.updateById(userAccountRecord);
            }
            //用户金额回退
            userAccountService.increaseBalance(userWithdraw.getUserId(), userWithdraw.getWithdrawAmount());
            UserAccount userAccount = userAccountService.selectUserAccount(userWithdraw.getUserId());
            if (Objects.isNull(userAccount)) {
                throw new BizException("用户账户有误");
            }
            //提现失败 增加技术账户记录
            userAccountRecordService.saveRecord(userWithdraw.getUserId(), userWithdraw.getWithdrawAmount(),
                    IncomeTypeEnum.IN.getCode(), AccountTypeEnum.WITHDRAW_FAIL.getCode(), userAccount.getBalance(), userWithdraw.getId());
            //发送转账失败通知邮件
            asyncTaskManager.execute(() -> sendTransMoneyMail(WithdrawStatusEnum.VERIFY_REJECT.getCode(), userWithdraw.getUserId(), request.getRemark(), userWithdraw.getWithdrawAmount()));
        }
        //增加后台审核记录
        createVerifyRecord(sysUserId, request);

    }

    private void createVerifyRecord(Integer sysUserId, WithdrawVerifyRequest request) {
        adminVerifyRecordService.save(request.getId(), sysUserId,
                request.getVerifyStatus(), request.getRemark(), AdminVerifyTypeEnum.WITHDRAW_VERIFY.getCode());
    }

    @Override
    public UserWithdrawResponse detail(Integer id) {
        UserWithdraw userWithdraw = baseMapper.selectById(id);
        if (Objects.isNull(userWithdraw)) {
            throw new BizException("提现数据有误");
        }
        UserWithdrawResponse response = new UserWithdrawResponse();
        BeanUtils.copyProperties(userWithdraw, response);
        response.setCreateTime(DateUtils.localDateTime2Date(userWithdraw.getCreateTime()));
        response.setUpdateTime(DateUtils.localDateTime2Date(userWithdraw.getUpdateTime()));
        if (!userWithdraw.getStatus().equals(NumberConstant.ONE)) {
            //查询审核记录
            List<AdminVerifyRecordResponse> verifyRecordResponseList = adminVerifyRecordService.
                    selectList(id, AdminVerifyTypeEnum.WITHDRAW_VERIFY.getCode());
            response.setVerifyRecordResponses(verifyRecordResponseList);
        }
        return response;
    }

    /**
     * 发送转账通知
     *
     * @param withdrawStatus 提现状态
     * @param userId         用户ID
     * @param remark         备注
     * @param withdrawAmount 提现金额
     */
    private void sendTransMoneyMail(Integer withdrawStatus, Integer userId, String remark, BigDecimal withdrawAmount) {
        UserInfo userInfo = userInfoService.getOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getUserId, userId));
        if (withdrawStatus.equals(WithdrawStatusEnum.VERIFY_PASS.getCode())) {
            mailService.sendMail(userInfo.getEmail(), String.format(EmailConstant.MONEY_TRANS_SUCCESS, userInfo.getEmail(), withdrawAmount.toString()));
        } else {
            mailService.sendMail(userInfo.getEmail(), String.format(EmailConstant.MONEY_TRANS_FAIL, userInfo.getEmail(), withdrawAmount.toString()));
        }
    }

    /**
     * 构建查询条件
     *
     * @param request 请求参数
     * @return LambdaQueryWrapper<UserWithdraw>
     */
    private LambdaQueryWrapper<UserWithdraw> buildWrapper(AdminUserWithdrawRequest request) {
        LambdaQueryWrapper<UserWithdraw> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Objects.nonNull(request.getId()), UserWithdraw::getId, request.getId());
        wrapper.eq(Objects.nonNull(request.getUserId()), UserWithdraw::getUserId, request.getUserId());
        wrapper.eq(Objects.nonNull(request.getStatus()), UserWithdraw::getStatus, request.getStatus());
        wrapper.like(StringUtils.isNotEmpty(request.getMobile()), UserWithdraw::getMobile, request.getMobile());
        wrapper.like(StringUtils.isNotEmpty(request.getNickname()), UserWithdraw::getNickname, request.getNickname());
        wrapper.like(StringUtils.isNotEmpty(request.getRealName()), UserWithdraw::getRealName, request.getRealName());
        wrapper.like(StringUtils.isNotEmpty(request.getAlipayAccount()), UserWithdraw::getAlipayAccount, request.getAlipayAccount());
        return wrapper;
    }


    private void checkParams(UserWithdrawRequest request, UserAccount userAccount, User user) {
        if (StringUtils.isEmpty(request.getAlipayAccount())) {
            throw new BizException("请输入支付宝账号");
        }
        if (Objects.isNull(userAccount)) {
            throw new BizException("账户有误");
        }
        if (Objects.isNull(user)) {
            throw new BizException("用户信息不存在");
        }
        if (Objects.isNull(request.getWithdrawAmount())) {
            throw new BizException("请输入体现金额");
        }
        if (new BigDecimal(request.getWithdrawAmount()).compareTo(userAccount.getBalance()) > 0) {
            throw new BizException("体现金额有误");
        }
    }
}
